import vue from '../main'
import store from '../store/index'
import { Loading, Message, Notification } from 'element-ui'
import {listenTf, tabLocalPlan, guideStore, batteryWarning} from './methods'
import { PARAMS } from "./params"
import { gitMapMethods, queryBranch } from './branch'
import { displayMap } from './map'
import { showWayPoints } from './waypoint'
import { ip } from './config'
export var ros, viewer, zoomview
export var OBJ = new DataServer();

function DataServer() {
    // TODO
};
//继承DATA属性，获取：DATA.DataServer.
DataServer.prototype.register = function (key, value, options) {
    if (this.hasOwnProperty(key)) {
        return;
    }
    var fnGetDefault = function () {
        return value;
    };
    var fnSetDefault = function (val) {
        if (val === value) {
            return;
        }
        if (val.hasOwnProperty('property')) {
            value = val.value;
        }
        else {
            value = val;
        }
    };
    var fnGet = options.fnGet || fnGetDefault;
    var fnSetOptions = options.fnSet || function () { };
    var fnSet = function (val) {
        fnSetDefault(val);
        fnSetOptions(val);
    };
    //Object.defineProperty：添加或修改属性
    //对象，属性名字，属性特征
    Object.defineProperty(this, key, {
        get: fnGet,
        set: fnSet
    });
};

DataServer.prototype.syncToLocalStorage = function () {
    //TODO
};

function registerObj() {
    return new Promise(function (resolve, reject) {
        OBJ.register('topic', {}, {});
        OBJ.register('tfMsg', {}, {});
        OBJ.register('cmdStringTopic', {}, {});
        OBJ.register('mapMsg', {}, {});
        OBJ.register('mapInfo', null, {});
        OBJ.register('navCtrlStatus', null, {});
        OBJ.register('mapStage', null, {});
        OBJ.register('wayPointsMsg', {}, {});
        OBJ.register('robotPoseMsg', {}, {});//add waypoints use
        OBJ.register('robotStage', {}, {});//robot maker
        OBJ.register('waypointsMessage', {}, {});
        OBJ.register('waypointsStage', {}, {});
        OBJ.register('mapXY', {}, {});
        OBJ.register('imgMapStage', {}, {});
        OBJ.register('laserScanStage', {}, {});
        OBJ.register('laserScanPose', {}, {});
        OBJ.register('footprintStage', {}, {});
        OBJ.register('globalPlanStage', {}, {});
        OBJ.register('tabLocalPlanStage', {}, {});
        OBJ.register('taskState', {}, {});
        OBJ.register('initialPoseStage', {}, {});
        
        resolve('register OBJ');
    })
}

//初始化ros
function rosInit() {
    return new Promise(function (resolve, reject) {
        // var url = window.location.hostname;
        ros = new ROSLIB.Ros({
            url: 'ws://' + ip + ':9090',
            groovyCompatibility: true
        });

        //链接到websocket服务器
        ros.on('connection', () => {
            console.log(`[INFO]Connected to rosbridge ${ip}.`);
            resolve('ros Connected');
            PARAMS.connecting = true;
            clearTimeout(PARAMS.reconnectSettimeout);
            if(PARAMS.connectFlg){
                window.location.reload();
            }
        });
        //关闭websocket服务器
        ros.on('close', () => {
            console.log(`[INFO]Rosbridge server ${ip} closed.`);
            Notification({
                title: vue.$t("titles.error"),
                message: vue.$t("messages.rosbridgeClosed"),
                type: 'error',
                position: 'top-left',
                offset: 100
            });                
            reject('Rosbridge连接已关闭');
            PARAMS.connecting = false;
            reconnect()
        });
        //关闭websocket服务器出错
        ros.on('error', () => {
            Notification({
                title: vue.$t("titles.error"),
                message: vue.$t("messages.rosbridgeError"),
                type: 'error',
                position: 'top-left',
                offset: 100
            });
            console.log("[INFO] rosbridge error")
            reject('Rosbridge连接失败');
            PARAMS.connecting = false;
            reconnect()
        });
        if(window.localStorage.getItem('role') === "developer"){
            store.commit("userRole", "developer");
        }
        if(window.localStorage.getItem('role') === "Administrator"){
            store.commit("userRole", "Administrator");
        }
    })
}

//检测重连
function reconnect () {
    PARAMS.connectFlg = true;
    if (PARAMS.connecting) {
        return
    }
    PARAMS.reconnectSettimeout && clearTimeout(PARAMS.reconnectSettimeout)
    PARAMS.reconnectSettimeout = setTimeout(() => {
        rosInit()
    }, PARAMS.timeout)
}


//initStage
function initStage() {
    return new Promise(function (resolve, reject) {
        var screenWidth = window.innerWidth || document.body.clientWidth || document.documentElement.clientWidth;
        var screenHeight = window.innerHeight || document.body.clientHeight || document.documentElement.clientHeight;
        var rMap = screenWidth / screenHeight;//比例
        var width = screenWidth;
        var height = screenHeight;
        if (screenWidth > screenHeight) {
            width = screenHeight * rMap;
            height = screenHeight;
        } else {
            width = screenWidth;
            height = screenWidth / rMap;
        }

        OBJ.mapInfo = {
            windowWidth: width,
            windowHeight: height
        };

        // Create the main viewer.
        viewer = new ROS2D.Viewer({
            divID: 'mapNavDiv',
            width: OBJ.mapInfo.windowWidth,
            height: OBJ.mapInfo.windowHeight
        });
        zoomview = new ROS2D.ZoomView({
            rootObject: viewer.scene
        });

        //实例化画布对象
        var stage = viewer.scene;
        createjs.Touch.enable(stage);//开启触摸，disable禁止触摸
        createjs.Ticker.setFPS(25);//一秒25帧

        /**
         * 拖拽移动画布
         * **/
        stage.enableMouseOver(10);//用到mouseover要加上这一句


        createjs.Touch.enable(stage);//移动端也支持点击移动事件，允许设备触控

        stage.mouseMoveOutside = true;//鼠标离开画布继续调用鼠标移动事件

        stage.on("mousedown", function (evt) {
            if (store.state.disabledMoveMap) {
                return
            } else {
                // keep a record on the offset between the mouse position and the container position. currentTarget will be the container that the event listener was added to:
                evt.currentTarget.offset = { x: this.x - evt.stageX, y: this.y - evt.stageY };
            }
        });
        stage.on("pressmove", function (evt) {
            if (store.state.disabledMoveMap) {
                return
            } else {
                // Calculate the new X and Y based on the mouse new position plus the offset.
                evt.currentTarget.x = evt.stageX + evt.currentTarget.offset.x;
                evt.currentTarget.y = evt.stageY + evt.currentTarget.offset.y;
                // make sure to redraw the stage to show the change:
                stage.update();
            }
        });
        stage.update();

        //刻度事件，实时监听变化
        createjs.Ticker.addEventListener('tick', function () {
            //更新，重新绘制画布
            stage.update();
        });
        resolve('initStage success')
    })
}

/**init topics
 * cmdStringTopic   -   提交查询地图话题
 * feedbackTopic    -   订阅地图和系统更新反馈
 * **/
function initTopics(){
    return new Promise(function(resolve, reject){
        //nav ctrl status topic
        var navCtrlStatusTopic = new ROSLIB.Topic({
            ros: ros,
            name: '/nav_ctrl_status',
            messageType: 'yocs_msgs/NavigationControlStatus'
        });
        OBJ.topic['navCtrlStatusTopic'] = navCtrlStatusTopic;
        var taskStateType = "info";
        var taskStateMessage = "";
        navCtrlStatusTopic.subscribe((message) => {
            OBJ.navCtrlStatus = message;
            store.commit("setNavControlStatus", message.status);
            if(message.status === -1){
                taskStateType = "error";
                taskStateMessage = vue.$t("taskState.error")
            }else if(message.status === 0){
                taskStateType = "info";
                taskStateMessage = vue.$t("taskState.exec")
            }else if(message.status === 1){
                taskStateType = "info";
                taskStateMessage = vue.$t("taskState.running") + message.waypoint_name
            }else if(message.status === 2){
                taskStateType = "info";
                taskStateMessage = vue.$t("taskState.pause") + message.waypoint_name
            }else if(message.status === 3){
                taskStateType = "success";
                taskStateMessage = vue.$t("taskState.completed") + message.waypoint_name
            }else if(message.status === 4){
                taskStateType = "success";
                taskStateMessage = vue.$t("taskState.canceled") +message.waypoint_name
            }
            Message({
                // message: vue.$t("taskState.taskState") + "："+ taskStateMessage,
                message: taskStateMessage,
                type: taskStateType,
                center: true,
                duration: 0,
                showClose: false,
                customClass: "bottomTaskStatus"
            });
        });

        //map
        var mapTopic = new ROSLIB.Topic({
            ros: ros,
            name: '/map_stream',
            messageType: 'scheduling_msgs/MapStream'
        });
        OBJ.topic['mapTopic'] = mapTopic;

        //map_edit
        var mapEditTopic = new ROSLIB.Topic({
            ros: ros,
            name: '/map_edit_stream',
            messageType: 'scheduling_msgs/MapStream'
        });
        OBJ.topic['mapEditTopic'] = mapEditTopic;

        //upload map
        var uploadMapTopic = new ROSLIB.Topic({
            ros: ros,
            name: '/map_stream_new',
            messageType:'scheduling_msgs/MapStream'
        });
        OBJ.topic['uploadMapTopic'] = uploadMapTopic;

        //upload map_edit
        var uploadMapEditTopic = new ROSLIB.Topic({
            ros: ros,
            name: '/map_edit_stream_new',
            messageType:'scheduling_msgs/MapStream'
        });
        OBJ.topic['uploadMapEditTopic'] = uploadMapEditTopic;


        //MapMetaData topic
        var MapMetaDataTopic = new ROSLIB.Topic({
            ros: ros,
            name: '/map_metadata',
            messageType: 'nav_msgs/MapMetaData'
        });
        OBJ.topic['MapMetaDataTopic'] = MapMetaDataTopic;

        //waypoints
        var wpTopic = new ROSLIB.Topic({
            ros: ros,
            name: '/waypoints',
            messageType: 'yocs_msgs/WaypointList'
        });
        OBJ.topic['wpTopic'] = wpTopic;

        //robot pose
        var robotPoseTopic = new ROSLIB.Topic({
            ros: ros,
            name: '/robot_pose',
            messageType: 'geometry_msgs/Pose',
            throttle_rate: 100
        });
        OBJ.topic['robotPoseTopic'] = robotPoseTopic;
        robotPoseTopic.subscribe(function (pose) {
            OBJ.robotPoseMsg = pose;
        });

        //手动定位topic
        var initialPoseTopic = new ROSLIB.Topic({
			ros: ros,
			name: '/initialpose',
			messageType: 'geometry_msgs/PoseWithCovarianceStamped'
        });
        OBJ.topic['initialPoseTopic'] = initialPoseTopic;

        //轨迹 topic
        var trajTopic = new ROSLIB.Topic({
            ros: ros,
            name: '/trajectories',
            messageType: 'yocs_msgs/TrajectoryList'
        });
        OBJ.topic['trajectoriesTopic'] = trajTopic;
        trajTopic.subscribe((message) => {
            store.commit('trajectoryList', message.trajectories);
        });

        //全局路径 topic
        var globalPathTopic = new ROSLIB.Topic({
            ros: ros,
            name: '/move_base/GlobalPlanner/plan',
            messageType: 'nav_msgs/Path',
        });
        OBJ.topic['globalPathTopic'] = globalPathTopic;

        //局部路径 topic
        var tabLocalPathTopic = new ROSLIB.Topic({
            ros: ros,
            name: '/move_base/TebLocalPlannerROS/local_plan',
            messageType: 'nav_msgs/Path',
        });
        OBJ.topic['tabLocalPathTopic'] = tabLocalPathTopic;

        //rosMode status
        let rosModeTopic = new ROSLIB.Topic({
            ros: ros,
            name: '/task_state',
            messageType: 'diagnostic_msgs/DiagnosticStatus'
        });
        OBJ.topic['rosModeTopic'] = rosModeTopic;
        rosModeTopic.subscribe((msg) => {
            msg.values.map(function (e, i) {
                if (e.key === 'auto_charge') {
                    store.commit('chargeStatus', e.value);
                    switch (e.value) {
                        case '0':
                            store.commit("switchBatteryStatus", false);
                            break;

                        case '1':
                            store.commit("switchBatteryStatus", true);
                            break;
                    }
                } else if (e.key === 'cartographer') {
                    OBJ.taskState = e.value;
                    if (e.value === "0") {
                        // showNewMap(false);
                        store.commit("setRosMode", PARAMS.rosMode.navigation);
                    } else if (e.value === "1") {
                        // showNewMap(true);
                        store.commit("setRosMode", PARAMS.rosMode.gmapping);
                    } else {

                    }
                }
            })
        })


        /**
         * buttery topic
         * charging: 充电中  warning：电量低  success：电量充足
         * **/
        var butteryTopic = new ROSLIB.Topic({
            ros: ros,
            name: '/battery',
            messageType: 'sensor_msgs/BatteryState'
        })
        OBJ.topic['butteryTopic'] = butteryTopic;
        butteryTopic.subscribe(function (msg) {
            if(msg.percentage){
                let butteryNum = Math.round(msg.percentage * 100);
                if( 0 <= butteryNum <= 100){
                    if (butteryNum <= 15) {
                        if(store.state.batteryStatus){
                            store.commit('batteryState', PARAMS.butteryStatus.charging);
                            batteryWarning();
                        }else{
                            store.commit('batteryState', PARAMS.butteryStatus.warning);
                            batteryWarning();
                        }
                    } else {
                        if(store.state.batteryStatus){
                            store.commit('batteryState', PARAMS.butteryStatus.charging);
                        }else{
                            store.commit('batteryState', PARAMS.butteryStatus.success);
                        }
                    }
                    store.commit('subButtery', butteryNum);
                    store.commit('showBattery', true)
                }
            }
        })


        //lasersan topic
        var laserScanTopic = new ROSLIB.Topic({
            ros: ros,
            name: '/scan_rectified',
            messageType: 'sensor_msgs/LaserScan',
            throttle_rate: 200
        });
        OBJ.topic['laserScanTopic'] = laserScanTopic;

        //轮廓 topic
        var footprintTopic = new ROSLIB.Topic({
            ros: ros,
            name: '/move_base/global_costmap/footprint',
            messageType: 'geometry_msgs/PolygonStamped'
        });
        OBJ.topic['footprintTopic'] = footprintTopic;


        //nav ctrltopic
        var navCtrlTopic = new ROSLIB.Topic({
            ros: ros,
            name: '/nav_ctrl',
            messageType: 'yocs_msgs/NavigationControl'
        });
        OBJ.topic['navCtrlTopic'] = navCtrlTopic;

        //add waypoint topic
        var addWaypointTopic = new ROSLIB.Topic({
            ros: ros,
            name: '/waypoint_add',
            messageType: 'yocs_msgs/Waypoint'
        });
        OBJ.topic['addWaypointTopic'] = addWaypointTopic;


        //remove waypoint topic
        var delWaypointTopic = new ROSLIB.Topic({
            ros: ros,
            name: '/waypoint_remove',
            messageType: 'yocs_msgs/Waypoint'
        });
        OBJ.topic['delWaypointTopic'] = delWaypointTopic;

        //add trajectory topic
        var addTrajectoryTopic = new ROSLIB.Topic({
            ros: ros,
            name: '/trajectory_add',
            messageType: 'yocs_msgs/Trajectory'
        });
        OBJ.topic['addTrajectoryTopic'] = addTrajectoryTopic;


        //remove trajectory topic
        var delTrajTopic = new ROSLIB.Topic({
            ros: ros,
            name: '/trajectory_remove',
            messageType: 'yocs_msgs/Trajectory'
        });
        OBJ.topic['delTrajTopic'] = delTrajTopic;

        /**
         * task_switch topic
         * frame_id     匹配到字符串为update_response就是更新的返回状态，后边为详情
         * seq          1：成功；0：失败
         * **/
        var taskSwitchTopic = new ROSLIB.Topic({
            ros: ros,
            name: '/task_switch',
            messageType: 'std_msgs/Header'
        });
        OBJ.topic['taskSwitchTopic'] = taskSwitchTopic;
        
        taskSwitchTopic.subscribe((res)=>{
            if(res.frame_id.startsWith("update_response")){
                switch(res.seq){
                    case 1:
                        Loading.service().close();
                        Notification({
                            title: vue.$t("titles.success"),
                            message: vue.$t("messages.updateSuccess") + ",请重启系统",
                            type: 'success',
                            position: 'top-left',
                            offset: 100
                        });
                        Message({
                            message: vue.$t("messages.updateSuccess"),
                            type: "success",
                            center: true,
                            duration: 0,
                            showClose: false,
                            customClass: "bottomTaskStatus"
                        });
                        break;
                    case 0:
                        Loading.service().close();
                        Notification({
                            title: vue.$t("titles.error"),
                            message: res.frame_id.replace(/update_response_/, ""),
                            type: 'error',
                            position: 'top-left',
                            offset: 100
                        });
                        Message({
                            message: vue.$t("messages.updateError") + "失败原因：" + res.frame_id.replace(/update_response_/, ""),
                            type: "error",
                            center: true,
                            duration: 0,
                            showClose: false,
                            customClass: "bottomTaskStatus"
                        });
                        break;
                    default:
                        break;
                }
            }
        })

        //请求分支列表
        queryBranch();

        /**
         * 返回所有状态信息
         * --GIT:dbparam    关于git的增删改查的关键词
         * hardware_id      增删改查关键词
         * level            0成功，1失败
         * message          回调信息
         * **/
        var diagnosticsAgg = new ROSLIB.Topic({
            ros: ros,
            name: '/diagnostics_agg',
            messageType: 'diagnostic_msgs/DiagnosticArray'
        });
        var robotsObject = {};
        diagnosticsAgg.subscribe((res)=>{
            // console.log(res)
            res.status.map((item, index)=>{
                switch (item.name) {
                    case '/GIT/dbparam':
                        Object.assign(robotsObject, {ALGORITHM: res.status[index]});
                        gitMapMethods(item)
                    default:
                        break;
                }
            })
        })

        //在线更新 topic
        var cmdTopic = new ROSLIB.Topic({
            ros: ros,
            name: '/cmd_string',
            messageType: 'std_msgs/String'
        });
        OBJ.topic['cmdTopic'] = cmdTopic;

        //小车移动topic
        var cmdVelTopic = new ROSLIB.Topic({
            ros: ros,
            name: '/cmd_vel',
            messageType: 'geometry_msgs/Twist'
        });
        OBJ.topic['cmdVelTopic'] = cmdVelTopic;

        //update topic
        var updateTopic = new ROSLIB.Topic({
            ros: ros,
            name: '/cmd_string',
            messageType: 'std_msgs/String'
        });
        OBJ.topic['updateTopic'] = updateTopic;

        //network topic
        var netWorkTopic = new ROSLIB.Topic({
            ros: ros,
            name: '/shell_string',
            messageType: 'std_msgs/String'
        });
        OBJ.topic['netWorkTopic'] = netWorkTopic;

        //预留
        // var mapShowStreamTopic = new ROSLIB.Topic({
        //     ros: ros,
        //     name: 'map_show_stream',
        //     messageType:'scheduling_msgs/MapStream'
        // });
        // OBJ.topic['mapShowStreamTopic'] = mapShowStreamTopic;

        //预留
        // var mapReflectionStreamTopic = new ROSLIB.Topic({
        //     ros: ros,
        //     name: 'map_reflection_stream',
        //     messageType:'scheduling_msgs/MapStream'
        // });
        // OBJ.topic['mapReflectionStreamTopic'] = mapReflectionStreamTopic;
        
        resolve('init topics')
    })
}

function promiseFun(...params){
    console.log(params)
    Loading.service().close();
}
$(() => {
    Loading.service({
        text: vue.$t("loading")
    })
    async function initSystem(){
        try{
            const register         = await registerObj();
            const rosInitFun       = await rosInit();
            const listenTfFun      = await listenTf();
            const initTopicsFun    = await initTopics();
            const initStageFun     = await initStage();
            const displayMapFun    = await displayMap();
            const showWayPointsFun = await showWayPoints();
            const tabLocalPlanFun  = await tabLocalPlan();
            const guideFun         = await guideStore();
            promiseFun(register, rosInitFun, listenTfFun, initTopicsFun, initStageFun, displayMapFun, showWayPointsFun, tabLocalPlanFun, guideFun)
            // promiseFun(guideFun)

        }catch(err){
            Loading.service().close();
            console.log(err)
        }
    }
    initSystem()
});

